/* PDCurses */

#include "pdcwin.h"

/* These variables are used to store information about the next
   Input Event. */

static INPUT_RECORD save_ip;
static MOUSE_STATUS old_mouse_status;
static DWORD event_count = 0;
static SHORT left_key;
static int key_count = 0;
static int save_press = 0;

#define KEV save_ip.Event.KeyEvent
#define MEV save_ip.Event.MouseEvent
#define REV save_ip.Event.WindowBufferSizeEvent

/************************************************************************
 *    Table for key code translation of function keys in keypad mode    *
 *    These values are for strict IBM keyboard compatibles only         *
 ************************************************************************/

typedef struct
{
	unsigned short normal;
	unsigned short shift;
	unsigned short control;
	unsigned short alt;
	unsigned short extended;
} KPTAB;

static KPTAB kptab[] =
{
	{0,          0,         0,           0,          0   }, /* 0  */
	{0,          0,         0,           0,          0   }, /* 1   VK_LBUTTON */
	{0,          0,         0,           0,          0   }, /* 2   VK_RBUTTON */
	{0,          0,         0,           0,          0   }, /* 3   VK_CANCEL  */
	{0,          0,         0,           0,          0   }, /* 4   VK_MBUTTON */
	{0,          0,         0,           0,          0   }, /* 5   */
	{0,          0,         0,           0,          0   }, /* 6   */
	{0,          0,         0,           0,          0   }, /* 7   */
	{0x08,       0x08,      0x7F,        ALT_BKSP,   0   }, /* 8   VK_BACK    */
	{0x09,       KEY_BTAB,  CTL_TAB,     ALT_TAB,    999 }, /* 9   VK_TAB     */
	{0,          0,         0,           0,          0   }, /* 10  */
	{0,          0,         0,           0,          0   }, /* 11  */
	{KEY_B2,     0x35,      CTL_PAD5,    ALT_PAD5,   0   }, /* 12  VK_CLEAR   */
	{0x0D,       0x0D,      CTL_ENTER,   ALT_ENTER,  1   }, /* 13  VK_RETURN  */
	{0,          0,         0,           0,          0   }, /* 14  */
	{0,          0,         0,           0,          0   }, /* 15  */
	{0,          0,         0,           0,          0   }, /* 16  VK_SHIFT   HANDLED SEPARATELY */
	{0,          0,         0,           0,          0   }, /* 17  VK_CONTROL HANDLED SEPARATELY */
	{0,          0,         0,           0,          0   }, /* 18  VK_MENU    HANDLED SEPARATELY */
	{0,          0,         0,           0,          0   }, /* 19  VK_PAUSE   */
	{0,          0,         0,           0,          0   }, /* 20  VK_CAPITAL HANDLED SEPARATELY */
	{0,          0,         0,           0,          0   }, /* 21  VK_HANGUL  */
	{0,          0,         0,           0,          0   }, /* 22  */
	{0,          0,         0,           0,          0   }, /* 23  VK_JUNJA   */
	{0,          0,         0,           0,          0   }, /* 24  VK_FINAL   */
	{0,          0,         0,           0,          0   }, /* 25  VK_HANJA   */
	{0,          0,         0,           0,          0   }, /* 26  */
	{0x1B,       0x1B,      0x1B,        ALT_ESC,    0   }, /* 27  VK_ESCAPE  */
	{0,          0,         0,           0,          0   }, /* 28  VK_CONVERT */
	{0,          0,         0,           0,          0   }, /* 29  VK_NONCONVERT */
	{0,          0,         0,           0,          0   }, /* 30  VK_ACCEPT  */
	{0,          0,         0,           0,          0   }, /* 31  VK_MODECHANGE */
	{0x20,       0x20,      0x20,        0x20,       0   }, /* 32  VK_SPACE   */
	{KEY_A3,     0x39,      CTL_PAD9,    ALT_PAD9,   3   }, /* 33  VK_PRIOR   */
	{KEY_C3,     0x33,      CTL_PAD3,    ALT_PAD3,   4   }, /* 34  VK_NEXT    */
	{KEY_C1,     0x31,      CTL_PAD1,    ALT_PAD1,   5   }, /* 35  VK_END     */
	{KEY_A1,     0x37,      CTL_PAD7,    ALT_PAD7,   6   }, /* 36  VK_HOME    */
	{KEY_B1,     0x34,      CTL_PAD4,    ALT_PAD4,   7   }, /* 37  VK_LEFT    */
	{KEY_A2,     0x38,      CTL_PAD8,    ALT_PAD8,   8   }, /* 38  VK_UP      */
	{KEY_B3,     0x36,      CTL_PAD6,    ALT_PAD6,   9   }, /* 39  VK_RIGHT   */
	{KEY_C2,     0x32,      CTL_PAD2,    ALT_PAD2,   10  }, /* 40  VK_DOWN    */
	{0,          0,         0,           0,          0   }, /* 41  VK_SELECT  */
	{0,          0,         0,           0,          0   }, /* 42  VK_PRINT   */
	{0,          0,         0,           0,          0   }, /* 43  VK_EXECUTE */
	{0,          0,         0,           0,          0   }, /* 44  VK_SNAPSHOT*/
	{PAD0,       0x30,      CTL_PAD0,    ALT_PAD0,   11  }, /* 45  VK_INSERT  */
	{PADSTOP,    0x2E,      CTL_PADSTOP, ALT_PADSTOP, 12  }, /* 46  VK_DELETE  */
	{0,          0,         0,           0,          0   }, /* 47  VK_HELP    */
	{0x30,       0x29,      0,           ALT_0,      0   }, /* 48  */
	{0x31,       0x21,      0,           ALT_1,      0   }, /* 49  */
	{0x32,       0x40,      0,           ALT_2,      0   }, /* 50  */
	{0x33,       0x23,      0,           ALT_3,      0   }, /* 51  */
	{0x34,       0x24,      0,           ALT_4,      0   }, /* 52  */
	{0x35,       0x25,      0,           ALT_5,      0   }, /* 53  */
	{0x36,       0x5E,      0,           ALT_6,      0   }, /* 54  */
	{0x37,       0x26,      0,           ALT_7,      0   }, /* 55  */
	{0x38,       0x2A,      0,           ALT_8,      0   }, /* 56  */
	{0x39,       0x28,      0,           ALT_9,      0   }, /* 57  */
	{0,          0,         0,           0,          0   }, /* 58  */
	{0,          0,         0,           0,          0   }, /* 59  */
	{0,          0,         0,           0,          0   }, /* 60  */
	{0,          0,         0,           0,          0   }, /* 61  */
	{0,          0,         0,           0,          0   }, /* 62  */
	{0,          0,         0,           0,          0   }, /* 63  */
	{0,          0,         0,           0,          0   }, /* 64  */
	{0x61,       0x41,      0x01,        ALT_A,      0   }, /* 65  */
	{0x62,       0x42,      0x02,        ALT_B,      0   }, /* 66  */
	{0x63,       0x43,      0x03,        ALT_C,      0   }, /* 67  */
	{0x64,       0x44,      0x04,        ALT_D,      0   }, /* 68  */
	{0x65,       0x45,      0x05,        ALT_E,      0   }, /* 69  */
	{0x66,       0x46,      0x06,        ALT_F,      0   }, /* 70  */
	{0x67,       0x47,      0x07,        ALT_G,      0   }, /* 71  */
	{0x68,       0x48,      0x08,        ALT_H,      0   }, /* 72  */
	{0x69,       0x49,      0x09,        ALT_I,      0   }, /* 73  */
	{0x6A,       0x4A,      0x0A,        ALT_J,      0   }, /* 74  */
	{0x6B,       0x4B,      0x0B,        ALT_K,      0   }, /* 75  */
	{0x6C,       0x4C,      0x0C,        ALT_L,      0   }, /* 76  */
	{0x6D,       0x4D,      0x0D,        ALT_M,      0   }, /* 77  */
	{0x6E,       0x4E,      0x0E,        ALT_N,      0   }, /* 78  */
	{0x6F,       0x4F,      0x0F,        ALT_O,      0   }, /* 79  */
	{0x70,       0x50,      0x10,        ALT_P,      0   }, /* 80  */
	{0x71,       0x51,      0x11,        ALT_Q,      0   }, /* 81  */
	{0x72,       0x52,      0x12,        ALT_R,      0   }, /* 82  */
	{0x73,       0x53,      0x13,        ALT_S,      0   }, /* 83  */
	{0x74,       0x54,      0x14,        ALT_T,      0   }, /* 84  */
	{0x75,       0x55,      0x15,        ALT_U,      0   }, /* 85  */
	{0x76,       0x56,      0x16,        ALT_V,      0   }, /* 86  */
	{0x77,       0x57,      0x17,        ALT_W,      0   }, /* 87  */
	{0x78,       0x58,      0x18,        ALT_X,      0   }, /* 88  */
	{0x79,       0x59,      0x19,        ALT_Y,      0   }, /* 89  */
	{0x7A,       0x5A,      0x1A,        ALT_Z,      0   }, /* 90  */
	{0,          0,         0,           0,          0   }, /* 91  VK_LWIN    */
	{0,          0,         0,           0,          0   }, /* 92  VK_RWIN    */
	{0,          0,         0,           0,          0   }, /* 93  VK_APPS    */
	{0,          0,         0,           0,          0   }, /* 94  */
	{0,          0,         0,           0,          0   }, /* 95  */
	{0x30,       0,         CTL_PAD0,    ALT_PAD0,   0   }, /* 96  VK_NUMPAD0 */
	{0x31,       0,         CTL_PAD1,    ALT_PAD1,   0   }, /* 97  VK_NUMPAD1 */
	{0x32,       0,         CTL_PAD2,    ALT_PAD2,   0   }, /* 98  VK_NUMPAD2 */
	{0x33,       0,         CTL_PAD3,    ALT_PAD3,   0   }, /* 99  VK_NUMPAD3 */
	{0x34,       0,         CTL_PAD4,    ALT_PAD4,   0   }, /* 100 VK_NUMPAD4 */
	{0x35,       0,         CTL_PAD5,    ALT_PAD5,   0   }, /* 101 VK_NUMPAD5 */
	{0x36,       0,         CTL_PAD6,    ALT_PAD6,   0   }, /* 102 VK_NUMPAD6 */
	{0x37,       0,         CTL_PAD7,    ALT_PAD7,   0   }, /* 103 VK_NUMPAD7 */
	{0x38,       0,         CTL_PAD8,    ALT_PAD8,   0   }, /* 104 VK_NUMPAD8 */
	{0x39,       0,         CTL_PAD9,    ALT_PAD9,   0   }, /* 105 VK_NUMPAD9 */
	{PADSTAR,   SHF_PADSTAR, CTL_PADSTAR, ALT_PADSTAR, 999 }, /* 106 VK_MULTIPLY*/
	{PADPLUS,   SHF_PADPLUS, CTL_PADPLUS, ALT_PADPLUS, 999 }, /* 107 VK_ADD     */
	{0,          0,         0,           0,          0   }, /* 108 VK_SEPARATOR     */
	{PADMINUS, SHF_PADMINUS, CTL_PADMINUS, ALT_PADMINUS, 999}, /* 109 VK_SUBTRACT*/
	{0x2E,       0,         CTL_PADSTOP, ALT_PADSTOP, 0   }, /* 110 VK_DECIMAL */
	{PADSLASH,  SHF_PADSLASH, CTL_PADSLASH, ALT_PADSLASH, 2 }, /* 111 VK_DIVIDE  */
	{KEY_F( 1 ),   KEY_F( 13 ), KEY_F( 25 ),   KEY_F( 37 ),  0   }, /* 112 VK_F1      */
	{KEY_F( 2 ),   KEY_F( 14 ), KEY_F( 26 ),   KEY_F( 38 ),  0   }, /* 113 VK_F2      */
	{KEY_F( 3 ),   KEY_F( 15 ), KEY_F( 27 ),   KEY_F( 39 ),  0   }, /* 114 VK_F3      */
	{KEY_F( 4 ),   KEY_F( 16 ), KEY_F( 28 ),   KEY_F( 40 ),  0   }, /* 115 VK_F4      */
	{KEY_F( 5 ),   KEY_F( 17 ), KEY_F( 29 ),   KEY_F( 41 ),  0   }, /* 116 VK_F5      */
	{KEY_F( 6 ),   KEY_F( 18 ), KEY_F( 30 ),   KEY_F( 42 ),  0   }, /* 117 VK_F6      */
	{KEY_F( 7 ),   KEY_F( 19 ), KEY_F( 31 ),   KEY_F( 43 ),  0   }, /* 118 VK_F7      */
	{KEY_F( 8 ),   KEY_F( 20 ), KEY_F( 32 ),   KEY_F( 44 ),  0   }, /* 119 VK_F8      */
	{KEY_F( 9 ),   KEY_F( 21 ), KEY_F( 33 ),   KEY_F( 45 ),  0   }, /* 120 VK_F9      */
	{KEY_F( 10 ),  KEY_F( 22 ), KEY_F( 34 ),   KEY_F( 46 ),  0   }, /* 121 VK_F10     */
	{KEY_F( 11 ),  KEY_F( 23 ), KEY_F( 35 ),   KEY_F( 47 ),  0   }, /* 122 VK_F11     */
	{KEY_F( 12 ),  KEY_F( 24 ), KEY_F( 36 ),   KEY_F( 48 ),  0   }, /* 123 VK_F12     */

	/* 124 through 218 */

	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},
	{0, 0, 0, 0, 0}, {0, 0, 0, 0, 0}, {0, 0, 0, 0, 0},

	{0x5B,       0x7B,      0x1B,        ALT_LBRACKET, 0  }, /* 219 */
	{0x5C,       0x7C,      0x1C,        ALT_BSLASH, 0   }, /* 220 */
	{0x5D,       0x7D,      0x1D,        ALT_RBRACKET, 0  }, /* 221 */
	{0,          0,         0x27,        ALT_FQUOTE, 0   }, /* 222 */
	{0,          0,         0,           0,          0   }, /* 223 */
	{0,          0,         0,           0,          0   }, /* 224 */
	{0,          0,         0,           0,          0   }, /* 225 */
	{0,          0,         0,           0,          0   }, /* 226 */
	{0,          0,         0,           0,          0   }, /* 227 */
	{0,          0,         0,           0,          0   }, /* 228 */
	{0,          0,         0,           0,          0   }, /* 229 */
	{0,          0,         0,           0,          0   }, /* 230 */
	{0,          0,         0,           0,          0   }, /* 231 */
	{0,          0,         0,           0,          0   }, /* 232 */
	{0,          0,         0,           0,          0   }, /* 233 */
	{0,          0,         0,           0,          0   }, /* 234 */
	{0,          0,         0,           0,          0   }, /* 235 */
	{0,          0,         0,           0,          0   }, /* 236 */
	{0,          0,         0,           0,          0   }, /* 237 */
	{0,          0,         0,           0,          0   }, /* 238 */
	{0,          0,         0,           0,          0   }, /* 239 */
	{0,          0,         0,           0,          0   }, /* 240 */
	{0,          0,         0,           0,          0   }, /* 241 */
	{0,          0,         0,           0,          0   }, /* 242 */
	{0,          0,         0,           0,          0   }, /* 243 */
	{0,          0,         0,           0,          0   }, /* 244 */
	{0,          0,         0,           0,          0   }, /* 245 */
	{0,          0,         0,           0,          0   }, /* 246 */
	{0,          0,         0,           0,          0   }, /* 247 */
	{0,          0,         0,           0,          0   }, /* 248 */
	{0,          0,         0,           0,          0   }, /* 249 */
	{0,          0,         0,           0,          0   }, /* 250 */
	{0,          0,         0,           0,          0   }, /* 251 */
	{0,          0,         0,           0,          0   }, /* 252 */
	{0,          0,         0,           0,          0   }, /* 253 */
	{0,          0,         0,           0,          0   }, /* 254 */
	{0,          0,         0,           0,          0   }  /* 255 */
};

static KPTAB ext_kptab[] =
{
	{0,          0,              0,              0,          }, /* MUST BE EMPTY */
	{PADENTER,   SHF_PADENTER,   CTL_PADENTER,   ALT_PADENTER}, /* 13 */
	{PADSLASH,   SHF_PADSLASH,   CTL_PADSLASH,   ALT_PADSLASH}, /* 111 */
	{KEY_PPAGE,  KEY_SPREVIOUS,  CTL_PGUP,       ALT_PGUP    }, /* 33 */
	{KEY_NPAGE,  KEY_SNEXT,      CTL_PGDN,       ALT_PGDN    }, /* 34 */
	{KEY_END,    KEY_SEND,       CTL_END,        ALT_END     }, /* 35 */
	{KEY_HOME,   KEY_SHOME,      CTL_HOME,       ALT_HOME    }, /* 36 */
	{KEY_LEFT,   KEY_SLEFT,      CTL_LEFT,       ALT_LEFT    }, /* 37 */
	{KEY_UP,     KEY_SUP,        CTL_UP,         ALT_UP      }, /* 38 */
	{KEY_RIGHT,  KEY_SRIGHT,     CTL_RIGHT,      ALT_RIGHT   }, /* 39 */
	{KEY_DOWN,   KEY_SDOWN,      CTL_DOWN,       ALT_DOWN    }, /* 40 */
	{KEY_IC,     KEY_SIC,        CTL_INS,        ALT_INS     }, /* 45 */
	{KEY_DC,     KEY_SDC,        CTL_DEL,        ALT_DEL     }, /* 46 */
	{PADSLASH,   SHF_PADSLASH,   CTL_PADSLASH,   ALT_PADSLASH}, /* 191 */
};

/* End of kptab[] */

void PDC_set_keyboard_binary( bool on )
{
	DWORD mode;

	PDC_LOG( ( "PDC_set_keyboard_binary() - called\n" ) );

	GetConsoleMode( pdc_con_in, &mode );
	SetConsoleMode( pdc_con_in, !on ? ( mode | ENABLE_PROCESSED_INPUT ) :
					( mode & ~ENABLE_PROCESSED_INPUT ) );
}

/* check if a key or mouse event is waiting */

bool PDC_check_key( void )
{
	if( key_count > 0 )
	{
		return TRUE;
	}

	GetNumberOfConsoleInputEvents( pdc_con_in, &event_count );

	return ( event_count != 0 );
}

/* _get_key_count returns 0 if save_ip doesn't contain an event which
   should be passed back to the user. This function filters "useless"
   events.

   The function returns the number of keys waiting. This may be > 1
   if the repetition of real keys pressed so far are > 1.

   Returns 0 on NUMLOCK, CAPSLOCK, SCROLLLOCK.

   Returns 1 for SHIFT, ALT, CTRL only if no other key has been pressed
   in between, and SP->return_key_modifiers is set; these are returned
   on keyup.

   Normal keys are returned on keydown only. The number of repetitions
   are returned. Dead keys (diacritics) are omitted. See below for a
   description.
*/

static int _get_key_count( void )
{
	int num_keys = 0, vk;

	PDC_LOG( ( "_get_key_count() - called\n" ) );

	vk = KEV.wVirtualKeyCode;

	if( KEV.bKeyDown )
	{
		/* key down */

		save_press = 0;

		if( vk == VK_CAPITAL || vk == VK_NUMLOCK || vk == VK_SCROLL )
		{
			/* throw away these modifiers */
		}
		else if( vk == VK_SHIFT || vk == VK_CONTROL || vk == VK_MENU )
		{
			/* These keys are returned on keyup only. */

			save_press = vk;
			switch( vk )
			{
				case VK_SHIFT:
					left_key = GetKeyState( VK_LSHIFT );
					break;
				case VK_CONTROL:
					left_key = GetKeyState( VK_LCONTROL );
					break;
				case VK_MENU:
					left_key = GetKeyState( VK_LMENU );
			}
		}
		else
		{
			/* Check for diacritics. These are dead keys. Some locales
			   have modified characters like umlaut-a, which is an "a"
			   with two dots on it. In some locales you have to press a
			   special key (the dead key) immediately followed by the
			   "a" to get a composed umlaut-a. The special key may have
			   a normal meaning with different modifiers. */

			if( KEV.uChar.UnicodeChar || !( MapVirtualKey( vk, 2 ) & 0x80000000 ) )
			{
				num_keys = KEV.wRepeatCount;
			}
		}
	}
	else
	{
		/* key up */

		/* Only modifier keys or the results of ALT-numpad entry are
		   returned on keyup */

		if( ( vk == VK_MENU && KEV.uChar.UnicodeChar ) ||
				( ( vk == VK_SHIFT || vk == VK_CONTROL || vk == VK_MENU ) &&
				  vk == save_press ) )
		{
			save_press = 0;
			num_keys = 1;
		}
	}

	PDC_LOG( ( "_get_key_count() - returning: num_keys %d\n", num_keys ) );

	return num_keys;
}

/* _process_key_event returns -1 if the key in save_ip should be
   ignored. Otherwise it returns the keycode which should be returned
   by PDC_get_key(). save_ip must be a key event.

   CTRL-ALT support has been disabled, when is it emitted plainly?  */

static int _process_key_event( void )
{
	int key =
#ifdef PDC_WIDE
		KEV.uChar.UnicodeChar;
#else
		KEV.uChar.AsciiChar;
#endif
	WORD vk = KEV.wVirtualKeyCode;
	DWORD state = KEV.dwControlKeyState;

	int idx;
	BOOL enhanced;

	SP->key_code = TRUE;

	/* Save the key modifiers. Do this first to allow to detect e.g. a
	   pressed CTRL key after a hit of NUMLOCK. */

	if( state & ( LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED ) )
	{
		SP->key_modifiers |= PDC_KEY_MODIFIER_ALT;
	}

	if( state & SHIFT_PRESSED )
	{
		SP->key_modifiers |= PDC_KEY_MODIFIER_SHIFT;
	}

	if( state & ( LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED ) )
	{
		SP->key_modifiers |= PDC_KEY_MODIFIER_CONTROL;
	}

	if( state & NUMLOCK_ON )
	{
		SP->key_modifiers |= PDC_KEY_MODIFIER_NUMLOCK;
	}

	/* Handle modifier keys hit by themselves */

	switch( vk )
	{
		case VK_SHIFT: /* shift */
			if( !SP->return_key_modifiers )
			{
				return -1;
			}

			return ( left_key & 0x8000 ) ? KEY_SHIFT_L : KEY_SHIFT_R;

		case VK_CONTROL: /* control */
			if( !SP->return_key_modifiers )
			{
				return -1;
			}

			return ( left_key & 0x8000 ) ? KEY_CONTROL_L : KEY_CONTROL_R;

		case VK_MENU: /* alt */
			if( !key )
			{
				if( !SP->return_key_modifiers )
				{
					return -1;
				}

				return ( left_key & 0x8000 ) ? KEY_ALT_L : KEY_ALT_R;
			}
	}

	/* The system may emit Ascii or Unicode characters depending on
	   whether ReadConsoleInputA or ReadConsoleInputW is used.

	   Normally, if key != 0 then the system did the translation
	   successfully. But this is not true for LEFT_ALT (different to
	   RIGHT_ALT). In case of LEFT_ALT we can get key != 0. So
	   check for this first. */

	if( key && ( !( state & LEFT_ALT_PRESSED ) ||
				 ( state & RIGHT_ALT_PRESSED ) ) )
	{
		/* This code should catch all keys returning a printable
		   character. Characters above 0x7F should be returned as
		   positive codes. */

		if( kptab[vk].extended == 0 )
		{
			SP->key_code = FALSE;
			return key;
		}
	}

	/* This case happens if a functional key has been entered. */

	if( ( state & ENHANCED_KEY ) && ( kptab[vk].extended != 999 ) )
	{
		enhanced = TRUE;
		idx = kptab[vk].extended;
	}
	else
	{
		enhanced = FALSE;
		idx = vk;
	}

	if( state & SHIFT_PRESSED )
	{
		key = enhanced ? ext_kptab[idx].shift : kptab[idx].shift;
	}

	else if( state & ( LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED ) )
	{
		key = enhanced ? ext_kptab[idx].control : kptab[idx].control;
	}

	else if( state & ( LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED ) )
	{
		key = enhanced ? ext_kptab[idx].alt : kptab[idx].alt;
	}

	else
	{
		key = enhanced ? ext_kptab[idx].normal : kptab[idx].normal;
	}

	if( key < KEY_CODE_YES )
	{
		SP->key_code = FALSE;
	}

	return key;
}

static int _process_mouse_event( void )
{
	static const DWORD button_mask[] = {1, 4, 2};
	short action, shift_flags = 0;
	int i;

	save_press = 0;
	SP->key_code = TRUE;

	memset( &SP->mouse_status, 0, sizeof( MOUSE_STATUS ) );

	SP->mouse_status.x = MEV.dwMousePosition.X;
	SP->mouse_status.y = MEV.dwMousePosition.Y;

	/* Handle scroll wheel */

	if( MEV.dwEventFlags == 4 )
	{
		SP->mouse_status.changes = ( MEV.dwButtonState & 0xFF000000 ) ?
								   PDC_MOUSE_WHEEL_DOWN : PDC_MOUSE_WHEEL_UP;

		memset( &old_mouse_status, 0, sizeof( old_mouse_status ) );

		return KEY_MOUSE;
	}

	if( MEV.dwEventFlags == 8 )
	{
		SP->mouse_status.changes = ( MEV.dwButtonState & 0xFF000000 ) ?
								   PDC_MOUSE_WHEEL_RIGHT : PDC_MOUSE_WHEEL_LEFT;

		memset( &old_mouse_status, 0, sizeof( old_mouse_status ) );

		return KEY_MOUSE;
	}

	action = ( MEV.dwEventFlags == 2 ) ? BUTTON_DOUBLE_CLICKED :
			 ( ( MEV.dwEventFlags == 1 ) ? BUTTON_MOVED : BUTTON_PRESSED );

	for( i = 0; i < 3; i++ )
		SP->mouse_status.button[i] =
			( MEV.dwButtonState & button_mask[i] ) ? action : 0;

	if( action == BUTTON_PRESSED && MEV.dwButtonState & 7 && SP->mouse_wait )
	{
		/* Check for a click -- a PRESS followed immediately by a release */

		if( !event_count )
		{
			napms( SP->mouse_wait );

			GetNumberOfConsoleInputEvents( pdc_con_in, &event_count );
		}

		if( event_count )
		{
			INPUT_RECORD ip;
			DWORD count;
			bool have_click = FALSE;

			PeekConsoleInput( pdc_con_in, &ip, 1, &count );

			for( i = 0; i < 3; i++ )
			{
				if( SP->mouse_status.button[i] == BUTTON_PRESSED &&
						!( ip.Event.MouseEvent.dwButtonState & button_mask[i] ) )
				{
					SP->mouse_status.button[i] = BUTTON_CLICKED;
					have_click = TRUE;
				}
			}

			/* If a click was found, throw out the event */

			if( have_click )
			{
				ReadConsoleInput( pdc_con_in, &ip, 1, &count );
			}
		}
	}

	SP->mouse_status.changes = 0;

	for( i = 0; i < 3; i++ )
	{
		if( old_mouse_status.button[i] != SP->mouse_status.button[i] )
		{
			SP->mouse_status.changes |= ( 1 << i );
		}

		if( SP->mouse_status.button[i] == BUTTON_MOVED )
		{
			/* Discard non-moved "moves" */

			if( SP->mouse_status.x == old_mouse_status.x &&
					SP->mouse_status.y == old_mouse_status.y )
			{
				return -1;
			}

			/* Motion events always flag the button as changed */

			SP->mouse_status.changes |= ( 1 << i );
			SP->mouse_status.changes |= PDC_MOUSE_MOVED;
			break;
		}
	}

	old_mouse_status = SP->mouse_status;

	/* Treat click events as release events for comparison purposes */

	for( i = 0; i < 3; i++ )
	{
		if( old_mouse_status.button[i] == BUTTON_CLICKED ||
				old_mouse_status.button[i] == BUTTON_DOUBLE_CLICKED )
		{
			old_mouse_status.button[i] = BUTTON_RELEASED;
		}
	}

	/* Check for SHIFT/CONTROL/ALT */

	if( MEV.dwControlKeyState & ( LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED ) )
	{
		shift_flags |= BUTTON_ALT;
	}

	if( MEV.dwControlKeyState & ( LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED ) )
	{
		shift_flags |= BUTTON_CONTROL;
	}

	if( MEV.dwControlKeyState & SHIFT_PRESSED )
	{
		shift_flags |= BUTTON_SHIFT;
	}

	if( shift_flags )
	{
		for( i = 0; i < 3; i++ )
		{
			if( SP->mouse_status.changes & ( 1 << i ) )
			{
				SP->mouse_status.button[i] |= shift_flags;
			}
		}
	}

	return KEY_MOUSE;
}

/* return the next available key or mouse event */

int PDC_get_key( void )
{
	SP->key_modifiers = 0L;

	if( !key_count )
	{
		DWORD count;

		ReadConsoleInput( pdc_con_in, &save_ip, 1, &count );
		event_count--;

		if( save_ip.EventType == MOUSE_EVENT ||
				save_ip.EventType == WINDOW_BUFFER_SIZE_EVENT )
		{
			key_count = 1;
		}
		else if( save_ip.EventType == KEY_EVENT )
		{
			key_count = _get_key_count();
		}
	}

	if( key_count )
	{
		key_count--;

		switch( save_ip.EventType )
		{
			case KEY_EVENT:
				return _process_key_event();

			case MOUSE_EVENT:
				return _process_mouse_event();

			case WINDOW_BUFFER_SIZE_EVENT:
				if( REV.dwSize.Y != LINES || REV.dwSize.X != COLS )
				{
					if( !SP->resized )
					{
						SP->resized = TRUE;
						SP->key_code = TRUE;
						return KEY_RESIZE;
					}
				}
		}
	}

	return -1;
}

/* discard any pending keyboard or mouse input -- this is the core
   routine for flushinp() */

void PDC_flushinp( void )
{
	PDC_LOG( ( "PDC_flushinp() - called\n" ) );

	FlushConsoleInputBuffer( pdc_con_in );
}

bool PDC_has_mouse( void )
{
	return TRUE;
}

int PDC_mouse_set( void )
{
	DWORD mode;

	/* If turning on mouse input: Set ENABLE_MOUSE_INPUT, and clear
	   all other flags, except processed input mode;
	   If turning off the mouse: Set QuickEdit Mode to the status it
	   had on startup, and clear all other flags, except etc. */

	GetConsoleMode( pdc_con_in, &mode );
	mode = ( mode & 1 ) | 0x0088;
	SetConsoleMode( pdc_con_in, mode | ( SP->_trap_mbe ?
										 ENABLE_MOUSE_INPUT : pdc_quick_edit ) );

	memset( &old_mouse_status, 0, sizeof( old_mouse_status ) );

	return OK;
}

int PDC_modifiers_set( void )
{
	return OK;
}
